﻿using BCCommon;
using BCCommon.Enums;
using BCCommon.Extensions;
using BCCommon.PaymentEnums;
using BCData.Common.FlowRecord;
using BCData.Common.SystemFinanceFlowRecord;
using BCData.Common.Wallet;
using BCData.Website.User.UserAuth;
using BCDto.Common.FlowRecord;
using BCDto.Common.Wallet;
using BCDto.Website.User;
using BCEntity.Common.FlowRecord;
using BCEntity.Common.SystemFinanceFlowRecord;
using BCEntity.Common.Wallet;
using BCService.Common.Payment.Payment;
using BCService.Utils;
using System;
using System.Collections.Generic;

namespace BCService.Common.Wallet
{
    public class WalletTransferService : IWalletTransferService
    {
        #region 私有变量

        private readonly IWalletData walletData;
        private readonly IUserAuthData userAuthData;
        private readonly IPaymentService paymentService;
        private readonly IUserFlowRecordData flowRecordData;
        private readonly IWalletTransferData walletTransferData;
        private readonly ISystemFinanceFlowRecordData systemFinanceFlowRecordData;

        #endregion 私有变量

        #region 构造函数

        public WalletTransferService(
            IWalletData walletData,
            IUserAuthData userAuthData,
            IPaymentService paymentService,
            IUserFlowRecordData flowRecordData,
            IWalletTransferData walletTransferData,
            ISystemFinanceFlowRecordData systemFinanceFlowRecordData)
        {
            this.walletData = walletData;
            this.userAuthData = userAuthData;
            this.paymentService = paymentService;
            this.flowRecordData = flowRecordData;
            this.walletTransferData = walletTransferData;
            this.systemFinanceFlowRecordData = systemFinanceFlowRecordData;
        }

        #endregion 构造函数

        #region 公共方法

        #region 提现审批

        public WalletTransferDto Approve(long id, UserDto userDto)
        {
            var entity = this.walletTransferData.Get(id);
            if (null == entity)
            {
                throw new ArgumentException("用户申请记录不存在");
            }
            if (entity.Status.In(CashOutStatusType.Failed.ToString(), CashOutStatusType.Processing.ToString(), CashOutStatusType.Success.ToString()))
            {
                throw new ArgumentException($"当前提现的状态为 {entity.Status.As<CashOutStatusType>().GetDisplayString()}，不能继续执行此操作。");
            }
            WalletEntity wallt = walletData.GetWalletByUserId(entity.UserId);
            if (wallt.Balance < entity.Amount)
            {
                throw new ArgumentException($"当前提现金额不能大于余额：{wallt.Balance}¥");
            }
            //微信、支付宝提现流程
            if (entity.TransferMode != CashOutChannelType.BankCard.ToString())
            {
                //1 调用支付接口
                var channelService = this.paymentService.GetChannelService(entity.AppType.AsEnum<SourceAppType>(), entity.PaymentChannelId.AsEnum<PaymentChannelType>(), entity.OSType.AsEnum<SourceOSType>());
                //2 微信、支付宝转账
                decimal amount = channelService.Transfer(entity.AppType.AsEnum<SourceAppType>(), entity.OSType.AsEnum<SourceOSType>(), entity.WalletTransferId, entity.Amount, entity.UserId, entity.OpenID, userDto);
                //3 更新钱包余额
                wallt.Balance = wallt.Balance - amount;
                walletData.Update(wallt);
                //4 创建资金流水记录
                var userFlowRecordEntity = ConvertUserFlowRecord(entity, wallt.Balance, amount);
                var systemFlowRecordEntity = ConvertSystemFlowRecord(entity, wallt.Balance, amount);
                //5 添加流水记录
                flowRecordData.AddAsync(userFlowRecordEntity);
                var task = systemFinanceFlowRecordData.Append(systemFlowRecordEntity);
                task.GetAwaiter().GetResult();
                string message = $"提现成功！金额为：{amount}元";
                //6 修改提现状态
                var resultDto = walletTransferData.Approve(id, CashOutStatusType.Success, DateTime.Now).As<WalletTransferDto>();
                return resultDto;
            }
            //如果是转账银行卡状态则为处理中
            else
            {
                var resultDto = walletTransferData.Approve(id, CashOutStatusType.Processing, null).As<WalletTransferDto>();
                return resultDto;
            }
            //TODO:增加消息推送
        }

        #endregion 提现审批

        #region 转账确认

        public WalletTransferDto TransferConfirm(long id, decimal amount, string ip)
        {
            var entity = this.walletTransferData.Get(id);
            if (null == entity)
            {
                throw new ArgumentException("用户申请记录不存在");
            }
            if (entity.Status != CashOutStatusType.Processing.ToString())
            {
                throw new ArgumentException("只有状态为 转账中， 才能继续执行此操作。");
            }
            if (amount <= 0)
            {
                throw new ArgumentException("转账金额不能为空。");
            }
            //1 更新钱包余额
            WalletEntity wallt = walletData.GetWalletByUserId(entity.UserId);
            wallt.Balance = wallt.Balance - amount;
            walletData.Update(wallt);
            //2 创建资金流水记录
            var userFlowRecordEntity = ConvertUserFlowRecord(entity, wallt.Balance, amount);
            var systemFlowRecordEntity = ConvertSystemFlowRecord(entity, wallt.Balance, amount);
            //3 添加流水记录
            flowRecordData.AddAsync(userFlowRecordEntity);
            var task = systemFinanceFlowRecordData.Append(systemFlowRecordEntity);
            task.GetAwaiter().GetResult();
            //4 修改提现状态
            var resultDto = walletTransferData.Approve(id, CashOutStatusType.Success, DateTime.Now).As<WalletTransferDto>();
            return resultDto;
        }

        #endregion 转账确认

        #region 获取单条提现记录

        public WalletTransferDto Get(long id)
        {
            return walletTransferData.Get(id).As<WalletTransferDto>();
        }

        #endregion 获取单条提现记录

        #region 用户提现记录列表

        public PageableList<WalletTransferDto> GetUserWalletTransfer(long userId, int index, int size)
        {
            var (dataList, dataCount) = walletTransferData.GetUserWalletTransfer(userId, index, size);

            return new PageableList<WalletTransferDto>()
            {
                Count = dataCount,
                Items = dataList.As<List<WalletTransferDto>>(),
                PageIndex = index,
                PageSize = size,
                ServerTime = DateTime.Now
            };
        }

        #endregion 用户提现记录列表

        #region 提现条件分页列表

        public PageableList<WalletTransferDto> Get(int pageIndex, int pageSize, CashOutStatusType? status, SourceAppType? appType,
            string userName, bool? @ascending = null, string phone = null)
        {
            var result = walletTransferData.Get(pageIndex, pageSize, out int dataCount, status, appType, userName, @ascending, phone);
            return new PageableList<WalletTransferDto>
            {
                Count = dataCount,
                Items = result.As<IEnumerable<WalletTransferDto>>()
            };
        }

        #endregion 提现条件分页列表

        #region 创建提现申请

        public WalletTransferDto Create(WalletTransferRequestDto requestDto, UserDto userDto)
        {
            var wallet = walletData.GetWalletByUserId(userDto.UserId);
            //1 判断用户支付密码是否正确
            if (requestDto.PayPassword.SHA256(userDto.Phone) != wallet.PayPassword)
            {
                throw new ArgumentException("支付密码错误!");
            }
            //2 判断用户余额是否充足
            if (requestDto.Amount > wallet.Balance)
            {
                throw new ArgumentException("您的余额不足，不能发起提现操作!");
            }
            //3 如果提现申请是支付宝或微信，则去拉去用户授权的信息
            string openId = string.Empty;
            if (requestDto.PaymentChannelId == CashOutChannelType.Alipay || requestDto.PaymentChannelId == CashOutChannelType.WeChat)
            {
                var userAuthInfo = userAuthData.Get(userDto.UserId, requestDto.PaymentChannelId.ToString()).Result;
                if (userAuthInfo == null)
                    throw new ArgumentException($"您的 {requestDto.PaymentChannelId.GetDescriptionString()} 未授权，不能发起提现操作!");
                openId = userAuthInfo.UnionId;
            }
            else
            {
                if (string.IsNullOrWhiteSpace(requestDto.BankCardNo))
                    throw new ArgumentException("您没有填写银行卡号，不能发起提现操作!");
            }

            //4 待处理提现申请的校验
            var existTransfer = walletTransferData.CheckPendingWithdraw(userDto.UserId);
            if (existTransfer)
            {
                throw new ArgumentException("您还有未完成的提现申请，不能重复操作!");
            }

            var entity = requestDto.As<WalletTransferEntity>();
            entity.Status = CashOutStatusType.Pending.ToString();
            entity.OpenID = openId;
            entity.UserId = userDto.UserId;
            var result = walletTransferData.Create(entity).As<WalletTransferDto>();
            return result;
        }

        #endregion 创建提现申请

        #region 拒绝提现申请

        public WalletTransferDto Reject(long id, WalletTransferRejectRequestDto dto)
        {
            var walletTransfer = walletTransferData.Get(id);
            if (walletTransfer == null)
            {
                throw new ArgumentException("用户申请记录不存在");
            }
            if (walletTransfer.Status.In(CashOutStatusType.Failed.ToString(), CashOutStatusType.Processing.ToString(), CashOutStatusType.Success.ToString()))
            {
                throw new ArgumentException($"当前提现的状态为 {walletTransfer.Status.As<CashOutStatusType>().GetDisplayString()}，不能继续执行此操作。");
            }

            var entity = this.walletTransferData.Reject(id, dto.RejectRefuse);

            string message = $"提现失败！金额为：{entity.Amount}元,失败原因：{ dto.RejectRefuse}，请您稍后再试";
            //TODO:添加推送消息记录

            return entity.As<WalletTransferDto>();
        }

        #endregion 拒绝提现申请

        #region 查看指定用户的账单明细

        /// <summary>
        /// 查看指定用户的账单明细
        /// </summary>
        /// <param name="pageIndex">分页页码</param>
        /// <param name="ascending">排序</param>
        /// <param name="pageSize">分页页数</param>
        /// <param name="userId">用户编号</param>
        /// <returns></returns>
        public PageableList<UserFlowRecordDto> GetBillingDetailsByUserId(long? userId, bool? ascending, int pageIndex, int pageSize)
        {
            var task = this.flowRecordData.GetFlowDetails(userId, ascending, pageIndex, pageSize);
            var result = task.GetAwaiter().GetResult();
            return new PageableList<UserFlowRecordDto>
            {
                Count = result.Item2,
                Items = result.Item1.As<List<UserFlowRecordDto>>()
            };
        }

        #endregion 查看指定用户的账单明细

        #endregion 公共方法

        #region 私有方法

        /// <summary>
        /// 获取风险级别
        /// </summary>
        /// <param name="amount">提现金额</param>
        /// <returns></returns>
        private SourceRiskLevelType GetRiskLevel(decimal amount)
        {
            if (amount >= 1000 && amount < 5000)
            {
                return SourceRiskLevelType.Low;
            }
            else if (amount >= 5000 && amount < 10000)
            {
                return SourceRiskLevelType.Middle;
            }
            else if (amount > 10000)
            {
                return SourceRiskLevelType.High;
            }
            else
            {
                return SourceRiskLevelType.Normal;
            }
        }

        /// <summary>
        /// 流水记录模型转换
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="balance">余额</param>
        /// <param name="amount">提现金额</param>
        /// <returns></returns>
        private UserFlowRecordEntity ConvertUserFlowRecord(WalletTransferExtendEntity entity, decimal balance, decimal amount)
        {
            UserFlowRecordEntity userFlowRecordEntity = new UserFlowRecordEntity
            {
                Balance = balance,
                CreateTime = DateTime.Now,
                Remark = $"提现: { string.Format("{0:n2}", amount)}元",
                FlowDirection = SourceFlowDirectionType.Outlay,
                FlowType = FlowType.CashOut,
                RiskLevel = GetRiskLevel(amount),
                OrderNo = entity.WalletTransferId.ToString()
            };
            userFlowRecordEntity.Amount = -amount;
            userFlowRecordEntity.Channel = entity.PaymentChannelId.AsEnum<PaymentChannelType>();
            userFlowRecordEntity.UserId = entity.UserId;
            userFlowRecordEntity.UserName = entity.UserName;

            return userFlowRecordEntity;
        }

        /// <summary>
        /// 系统资金流水记录
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="balance"></param>
        /// <param name="amount"></param>
        /// <returns></returns>
        private SystemFinanceFlowRecordEntity ConvertSystemFlowRecord(WalletTransferExtendEntity entity, decimal balance, decimal amount)
        {
            SystemFinanceFlowRecordEntity recordEntity = new SystemFinanceFlowRecordEntity
            {
                OrderNo = entity.WalletTransferId.ToString(),
                UserId = entity.UserId,
                UserName = entity.UserName,
                FlowDirection = SourceFlowDirectionType.Outlay,
                Amount = amount,
                Balance = balance + amount,
                Channel = entity.PaymentChannelId.AsEnum<PaymentChannelType>(),
                CreateTime = DateTime.Now,
                Remark = $"提现: { string.Format("{0:n2}", amount)}元",
                FlowType = FlowType.CashOut,
            };

            return recordEntity;
        }

        #endregion 私有方法
    }
}